package com.ar4j.handler;

import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

import net.sf.cglib.proxy.MethodProxy;

import com.ar4j.ActiveRecord;
import com.ar4j.ActiveRecordContext;
import com.ar4j.ActiveRecordMetadata;
import com.ar4j.sql.SqlUtils;
import com.ar4j.util.CollectionUtils;

/**
 * A handler for active record find operations
 */
public class DeleteMethodHandler implements IMethodHandler {
  private String deleteQuery;
  private ReentrantLock queryCreateLock = new ReentrantLock();
  
  @Override
  public Object intercept(ActiveRecordMetadata metadata, ActiveRecordContext context, Object target, Method method, Object[] args, MethodProxy proxy) 
    throws Throwable {
    
    // compose the query if its the first time we are running
    if(deleteQuery == null) {
      queryCreateLock.lock();
      try {
        if(deleteQuery == null) {
          deleteQuery = composeDeleteQuery(metadata);
        }
      } finally {
        queryCreateLock.unlock();
      }
    }
    
    // make sure we have a template first
    if(context.getSimpleTemplate() == null) {
      throw new IllegalStateException("Cannot execute delete on an active record that does not have a datasource set");
    }
    
    ActiveRecord<?> record = (ActiveRecord<?>) target;
    context.getSimpleTemplate().update(deleteQuery, CollectionUtils.getSingleValueMap(metadata.getIdentifierPropertyName(), record.getIdentifier()));
    record.setProperty(metadata.getIdentifierPropertyName(), null);
    
    return null;
  }

  private String composeDeleteQuery(ActiveRecordMetadata metadata) {
    StringBuilder sql = new StringBuilder();
    
    sql.append("DELETE FROM ");
    sql.append(metadata.getTableName());
    SqlUtils.appendWhereClause(sql, 
        CollectionUtils.getSingleValueCollection(metadata.getIdentifierPropertyName()), 
        new HashSet<String>(), 
        null,
        metadata.getPropertyColumnNameMap());
    
    return sql.toString();
  }
  
  @Override
  public String toString() {
    return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
  }

}
